package com.share.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.extra.mail.MailUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.share.utils.AliYunParameterUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/api/code")
public class CodeController {

    @Autowired
    private RedisTemplate<String, String> redis;
    private static String uuid = UUID.randomUUID().toString();

    // 获取手机号验证码
    @GetMapping("/getPhoneCode")
    public void getPhoneCode(@RequestParam String phone) {
        SendSmsResponse sendSmsResponse = null;
        // 1. 准备好短信模板变量 —— 验证码 code
        int code = (int) ((Math.random() * 9000) + 1000);
        log.info("手机号验证码" + code);
        redis.opsForValue().set("phoneCodes:" + phone, String.valueOf(code), 5, TimeUnit.MINUTES);

        try {
            // 2. 可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");

            // 3. 初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", AliYunParameterUtil.accessKeyId, AliYunParameterUtil.accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", AliYunParameterUtil.PRODUCT, AliYunParameterUtil.DOMAIN);
            IAcsClient acsClient = new DefaultAcsClient(profile);

            //4.组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();

            //必填:待发送手机号
            request.setPhoneNumbers(phone);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(AliYunParameterUtil.signName);
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(AliYunParameterUtil.templateCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam(String.format("{\"code\":\"%s\"}", code));     // 这里是 json

            //5.hint 此处可能会抛出异常，注意catch
            sendSmsResponse = acsClient.getAcsResponse(request);
            if (sendSmsResponse != null && "OK".equals(sendSmsResponse.getCode())) {
                log.info("短信发送成功！");
                redis.opsForValue().set(phone, String.valueOf(code), 5, TimeUnit.MINUTES);       // 将手机号作为 key 放入验证码  有效期五分钟
            } else {
                log.error("短信发送失败！错误码: {}, 错误信息: {}",
                        sendSmsResponse == null ? "未知" : sendSmsResponse.getCode(),
                        sendSmsResponse == null ? "未知" : sendSmsResponse.getMessage());
                throw new RuntimeException("短信发送失败");
            }
        } catch (Exception e) {
            System.out.println("引起异常的原因------>" + e);
            System.out.println("异常信息------>" + e.getMessage());
            System.out.println("短信发送失败！");
            throw new IllegalArgumentException("手机号码不能为空");
        }
    }

    // 校验手机号验证码
    public boolean verifyPhoneCode(String phone, String code) {
        // 1. 拿到 redis中存储的手机号验证码
        String authCode = redis.opsForValue().get("phoneCodes:" + phone);

        // 2. 如果验证码过期
        if (authCode == null) {
            throw new IllegalArgumentException("验证码已过期或不存在");
        }
        log.info("正确的手机号验证码" + authCode);

        // 3. 校验验证码的有效性
        if (code == null || code.isEmpty() || !code.equals(authCode)) {
            return false;
        }

        // 4. 验证成功将该验证码删掉
//        redis.delete("phoneCodes:" + phone);
        return true;
    }

    // 获取真人验证码
    @GetMapping("/getAuthCode")
    public void getAuthCode(HttpServletResponse response) throws IOException {
        // 1. 定义图形验证码的长、宽、验证码字符数、干扰线宽度
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 4);
        String code = captcha.getCode();
        log.info("生成的验证码" + code);

        // 2. 将验证码存到 redis中  五分钟内有效  过期清除 redis中的验证码
        redis.opsForValue().set("authCodes:" + uuid, code, 5, TimeUnit.MINUTES);

        // 3. 将验证码用流写出
        response.setContentType("image/png");
        ServletOutputStream outputStream = response.getOutputStream();
        captcha.write(outputStream);
        outputStream.close();     // Servlet 的 OutputStream 记得自行关闭哦！
    }

    // 校验真人验证码
    public boolean verifyAuthCode(String code) {
        // 1. 拿到 redis中存储的真人验证码
        String authCode = redis.opsForValue().get("authCodes:" + uuid);
        log.info("正确的验证码：{}", authCode);

        // 2. 如果验证码过期
        if (authCode == null) {
            throw new IllegalArgumentException("验证码已过期或不存在");
        }

        // 3. 校验验证码的有效性
        if (!code.equals(authCode)) {
            return false;
        }

        redis.delete("authCodes:" + authCode);      // 验证成功将该验证码删掉
        return true;
    }

}
